/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#include "at32f421.h"
#include "drv_i2c.h"
#include "rtthread.h"


#define SOFT_I2C_SPEED_100KHZ 9
#define SOFT_I2C_SPEED_400KHZ 1
#define GPIO_PORT_I2C GPIOA				  /* GPIO端口 */
#define RCC_I2C_PORT CRM_GPIOA_PERIPH_CLOCK /* GPIO端口时钟 */
#define I2C_SCL_PIN GPIO_PINS_11			  /* 连接到SCL时钟线的GPIO */
#define I2C_SDA_PIN GPIO_PINS_12			  /* 连接到SDA数据线的GPIO */


#define I2C_SCL_1() GPIO_PORT_I2C->scr = I2C_SCL_PIN			   /* SCL = 1 */
#define I2C_SCL_0() GPIO_PORT_I2C->clr = I2C_SCL_PIN			   /* SCL = 0 */
#define I2C_SDA_1() GPIO_PORT_I2C->scr = I2C_SDA_PIN			   /* SDA = 1 */
#define I2C_SDA_0() GPIO_PORT_I2C->clr = I2C_SDA_PIN			   /* SDA = 0 */
#define I2C_SCL_READ() ((GPIO_PORT_I2C->idt & I2C_SCL_PIN) != 0)    /* 读SCL口线状态 */
#define I2C_SDA_READ() ((GPIO_PORT_I2C->idt & I2C_SDA_PIN) != 0)    /* 读SDA口线状态 */

static uint16_t softI2cDelayT=SOFT_I2C_SPEED_400KHZ;

void soft_i2c_NAck(void);
void soft_i2c_Ack(void);

void drv_soft_i2c_init(void)
{
    gpio_init_type gpio_init_struct;

    /* enable the usart2 and gpio clock */
    crm_periph_clock_enable(RCC_I2C_PORT, TRUE);
    gpio_default_para_init(&gpio_init_struct);
    /* configure the usart2 tx/rx pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
    gpio_init_struct.gpio_pins = I2C_SCL_PIN | I2C_SDA_PIN;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIO_PORT_I2C, &gpio_init_struct);
}
void soft_i2c_set_speed(uint16_t s)
{
	softI2cDelayT=SOFT_I2C_SPEED_400KHZ*s;
}
void soft_i2c_set_speed_100kHz(void)
{
	softI2cDelayT=SOFT_I2C_SPEED_100KHZ;
}
void soft_i2c_set_speed_400kHz(void)
{
	softI2cDelayT=SOFT_I2C_SPEED_400KHZ;
}
void SoftDelayUs(uint16_t us)
{
	// volatile 防止编译器做优化
	volatile u16 i = 0;
	while (us--)
	{
		i = 7;//情况修改，不同编译环境，实际运行效果会不一样，
		while (--i);
	}
}
void soft_i2c_Delay()
{
	SoftDelayUs(softI2cDelayT);
}
void soft_i2c_Start(void)
{
	/* 当SCL高电平时，SDA出现一个下跳沿表示I2C总线启动信号 */

	I2C_SDA_1();
	I2C_SCL_1();
	soft_i2c_Delay();
	I2C_SDA_0();
	soft_i2c_Delay();
	I2C_SCL_0();
	soft_i2c_Delay();
}

/*
*********************************************************************************************************
*	函 数 名: soft_i2c_Start
*	功能说明: CPU发起I2C总线停止信号
*	形    参：无
*	返 回 值: 无
*********************************************************************************************************
*/
void soft_i2c_Stop(void)
{

	/* 当SCL高电平时，SDA出现一个上跳沿表示I2C总线停止信号 */
	I2C_SDA_0();
	soft_i2c_Delay();
	I2C_SCL_1();
	soft_i2c_Delay();
	I2C_SDA_1();
	soft_i2c_Delay();
}

/*
*********************************************************************************************************
*	函 数 名: soft_i2c_SendByte
*	功能说明: CPU向I2C总线设备发送8bit数据
*	形    参：_ucByte ： 等待发送的字节
*	返 回 值: 无
*********************************************************************************************************
*/
void soft_i2c_SendByte(uint8_t _ucByte)
{
	uint8_t i;
	#if IRQ_BLOCK
	__disable_irq();
	#endif
	/* 先发送字节的高位bit7 */
	for (i = 0; i < 8; i++)
	{
		I2C_SCL_0();//change data at low
		soft_i2c_Delay();
		if (_ucByte & 0x80)
		{
			I2C_SDA_1();
		}
		else
		{
			I2C_SDA_0();
		}
		soft_i2c_Delay();
		I2C_SCL_1(); //hold data at high
		soft_i2c_Delay();
		soft_i2c_Delay();
		_ucByte <<= 1; /* 左移一个bit */

	}
	I2C_SCL_0();//change data at low
	I2C_SDA_1(); // 释放总线
	soft_i2c_Delay();
	#if IRQ_BLOCK
	__enable_irq();
	#endif

}
void soft_i2c_Send16Bits(uint16_t _16bits)
{
	uint8_t i;

	/* 先发送字节的高位bit7 */
	for (i = 0; i < 16; i++)
	{
		if (_16bits & 0x8000)
		{
			I2C_SDA_1();
		}
		else
		{
			I2C_SDA_0();
		}
		soft_i2c_Delay();
		I2C_SCL_1();
		soft_i2c_Delay();
		I2C_SCL_0();
		if (i == 7)
		{
			I2C_SDA_1(); // 释放总线
		}
		soft_i2c_Delay();
		_16bits <<= 1; /* 左移一个bit */
		// soft_i2c_Delay();
	}
	I2C_SDA_1(); // 释放总线
}

/*
*********************************************************************************************************
*	函 数 名: soft_i2c_ReadByte
*	功能说明: CPU从I2C总线设备读取8bit数据
*	形    参：0:NAck 1:Ack
*	返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t soft_i2c_ReadByte(u8 ack)
{
	uint8_t i;
	uint8_t value;
	#if IRQ_BLOCK
	__disable_irq();
	#endif
	/* 读到第1个bit为数据的bit7 */

	value = 0;
	I2C_SDA_1(); // 释放总线
	soft_i2c_Delay();
	for (i = 0; i < 8; i++)
	{
		value <<= 1;
		I2C_SCL_1();
		soft_i2c_Delay();
		if (I2C_SDA_READ())
		{
			value++;
		}
		I2C_SCL_0();
		soft_i2c_Delay();
	}

	soft_i2c_Delay();
	if (ack == 0)
		soft_i2c_NAck();
	else
		soft_i2c_Ack();
	return value;
}
uint16_t soft_i2c_Read16Bits(uint16_t ack)
{
	uint8_t i;
	uint16_t value;

	soft_i2c_Delay();
	value = 0;
	for (i = 0; i < 16; i++)
	{
		value <<= 1;
		I2C_SCL_1();
		soft_i2c_Delay();
		if (I2C_SDA_READ())
		{
			value|=0x0001;
		}
		//I2C_SCL_1();
		//soft_i2c_Delay();
		I2C_SCL_0();
		soft_i2c_Delay();
	}

	soft_i2c_Delay();
	if (ack == 0)
		soft_i2c_NAck();
	else
		soft_i2c_Ack();
	return value;
}
/*
*********************************************************************************************************
*	函 数 名: soft_i2c_WaitAck
*	功能说明: CPU产生一个时钟，并读取器件的ACK应答信号
*	形    参：无
*	返 回 值: 返回0表示正确应答，1表示无器件响应
*********************************************************************************************************
*/
uint8_t soft_i2c_WaitAck(void)
{
	uint8_t re;

	I2C_SDA_1();	 /* CPU释放SDA总线 */
	soft_i2c_Delay();
	soft_i2c_Delay();
	I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
	soft_i2c_Delay();
	soft_i2c_Delay();
	if (I2C_SDA_READ()) /* CPU读取SDA口线状态 */
	{
		re = 1;
	}
	else
	{
		re = 0;
	}
	I2C_SCL_0();
	soft_i2c_Delay();
	soft_i2c_Delay();
	return re;
}

/*
*********************************************************************************************************
*	函 数 名: soft_i2c_Ack
*	功能说明: CPU产生一个ACK信号
*	形    参：无
*	返 回 值: 无
*********************************************************************************************************
*/
void soft_i2c_Ack(void)
{
	I2C_SDA_0(); /* CPU驱动SDA = 0 */
	soft_i2c_Delay();
	I2C_SCL_1(); /* CPU产生1个时钟 */
	soft_i2c_Delay();
	I2C_SCL_0();
	soft_i2c_Delay();
	I2C_SDA_1(); /* CPU释放SDA总线 */
	soft_i2c_Delay();
}

/*
*********************************************************************************************************
*	函 数 名: soft_i2c_NAck
*	功能说明: CPU产生1个NACK信号
*	形    参：无
*	返 回 值: 无
*********************************************************************************************************
*/
void soft_i2c_NAck(void)
{
	I2C_SDA_1(); /* CPU驱动SDA = 1 */
	// soft_i2c_Delay();
	I2C_SCL_1(); /* CPU产生1个时钟 */
	soft_i2c_Delay();
	I2C_SCL_0();
	soft_i2c_Delay();
	// soft_i2c_Delay();
	// I2C_SDA_1(); /* CPU释放SDA总线 */
}

/**
 * @brief  software i2c write values to slave device reg
 * @note
 * @param  slaveAddr:
 * @param  regAddr:
 * @param  writeBuffer:
 * @param  numToWrite:
 * @retval 0: when everything is ok
 */
uint8_t soft_i2c_write(uint8_t slaveAddr, uint8_t regAddr, uint8_t *writeBuffer, uint8_t numToWrite)
{
	uint8_t error = 0;

	soft_i2c_Start();
	soft_i2c_SendByte(slaveAddr);
	if (soft_i2c_WaitAck())
	{
		error |= 0x01;
	}
	soft_i2c_SendByte(regAddr);
	if (soft_i2c_WaitAck())
	{
		error |= 0x02;
	}
	for (u8 i = 0; i < numToWrite; i++)
	{
		soft_i2c_SendByte(writeBuffer[i]);
		if (soft_i2c_WaitAck())
		{
			error |= 0x04;
		}
	}
	soft_i2c_Stop();

	return error;
}

//测试SCL IO，无法翻转电平时返回1错误。正常时返回0
int8_t soft_i2c_scl_test(void)
{
	I2C_SCL_0();//写0
	soft_i2c_Delay();
	if(I2C_SCL_READ())
	{
		//读到1，错误！
		return 1;
	}

	I2C_SCL_1(); //写1
	soft_i2c_Delay();
	if(!I2C_SCL_READ())
	{
		//读到0，错误！
		return 2;
	}
	return 0;
}
//测试SDA IO，无法翻转电平时返回1错误。正常时返回0
int8_t soft_i2c_sda_test(void)
{
	I2C_SDA_0();//写0
	soft_i2c_Delay();
	if(I2C_SDA_READ())
	{
		//读到1，错误！
		return 1;
	}
	I2C_SDA_1(); //写1
	soft_i2c_Delay();
	if(!I2C_SDA_READ())
	{
		//读到0，错误！
		return 2;
	}
	return 0;
}
void soft_i2c_scan_device(void)
{
	rt_kprintf("soft_i2c_scan_device...\n");
	soft_i2c_set_speed_100kHz();
	if(soft_i2c_sda_test() || soft_i2c_scl_test())
	{
		if(soft_i2c_sda_test())
		{
			rt_kprintf("Soft i2c SDA error!\n");
		}
		if(soft_i2c_scl_test())
		{
			rt_kprintf("Soft i2c SCL error!\n");
		}
		return;
	}
	uint8_t dcnt=0;
	for (uint8_t i = 0; i <= 0xfe; i++)
	{
		soft_i2c_Start();
		soft_i2c_SendByte(i);
		uint8_t ack = soft_i2c_WaitAck();

		soft_i2c_Stop();

		if(ack)
		{
			// rt_kprintf("no ack at:0x%x\n",i);
		}
		else
		{
			dcnt++;
			rt_kprintf("--------------------find:0x%x ok\n",i);
		}
		rt_thread_mdelay(5);
	}
	// rt_kprintf("dcnt:%d\n",dcnt);
	if(dcnt == 0)
	{
		rt_kprintf("can't find any i2c device.\n\n\n");
	}
}

/**
 * @brief  read values for slave device reg
 * @note
 * @param  slaveAddr:
 * @param  regAddr:
 * @param  readBuffer:
 * @param  numToRead:
 * @retval 0: when everything is ok
 */
uint8_t soft_i2c_read(uint8_t slaveAddr, uint8_t regAddr, uint8_t *readBuffer, uint8_t numToRead)
{
	uint8_t error = 0;

	soft_i2c_Start();
	soft_i2c_SendByte(slaveAddr);
	if (soft_i2c_WaitAck())
	{
		error |= 0x01;
	}
	soft_i2c_SendByte(regAddr);
	if (soft_i2c_WaitAck())
	{
		error |= 0x02;
	}

	soft_i2c_Start();
	soft_i2c_SendByte(slaveAddr | 0x01);
	if (soft_i2c_WaitAck())
	{
		error |= 0x04;
	}

	for (u8 i = 0; i < (numToRead - 1); i++)
	{
		*readBuffer = soft_i2c_ReadByte(1);
		readBuffer++;
	}
	*readBuffer = soft_i2c_ReadByte(0);
	soft_i2c_Stop();

	return error;
}
